<?php
/**
 * Zhub - A PHP Framework For API Developer
 *
 * This file is part of the Zhub package.
 *
 * (c) YiLong Fan <fantiq@163.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @author fanyilong <fantiq@163.com>
 * @copyright 2017 fanyilong. All rights reserved.
 * @package Zhub
 * @date 18-3-19
 */

namespace Zhub\Application\Http\Event;


use Zhub\Application\Http\Kernel;
use Zhub\Application\Http\RoutingContext;
use Zhub\Event\Event;
use Zhub\HttpMessage\Response;
use Zhub\HttpMessage\ResponseStatus;
use Zhub\Route\Exceptions\RouteNotFoundException;
use Zhub\Route\RouteStruct;

class AppEvent extends Event implements HttpEvent
{
    protected function boot()
    {
        $this->orderChain(
            $this->bind(self::START, function (Kernel $app) {
                return $this->onStart($app);
            }),
            $this->bind(self::BOOTSTRAP, function (Kernel $app) {
                return $this->onBootstrap($app);
            }),
            $this->bind(self::REQUEST, function (Kernel $app) {
                return $this->onRequest($app);
            }),
            $this->bind(self::ROUTE_MATCH, function (Kernel $app) {
                return $this->onRouteMatch($app);
            }),
            $this->bind(self::DISPATCH, function (Kernel $app, RouteStruct $struct) {
                return $this->onDispatch($app, $struct);
            }),
            $this->bind(self::RESPONSE, function (Kernel $app, $response) {
                return $this->onResponse($app, $response);
            }),
            $this->bind(self::END, function (Kernel $app) {
                return $this->onEnd($app);
            })
        );
    }

    public function onStart(Kernel $app = null)
    {
        return $app;
    }

    public function onBootstrap(Kernel $app = null)
    {
        return $app;
    }

    public function onRequest(Kernel $app = null)
    {
        return $app;
    }

    public function onRouteMatch(Kernel $app)
    {
        $request = $app->getRequest();
        $route = $app->getRoute();
        if ($request->getUrl()->getPath() === 'favicon.ico') {
            exit(1001);
        }
        $struct = null;
        try {
            $struct = $route->match($request->getUrl()->getPath());
        }
        catch (RouteNotFoundException $e) {
            // 时间调用链 还是需要能够跳过的功能
        }

        return [
            $app,
            $struct
        ];

    }

    public function onDispatch(Kernel $app, RouteStruct $route = null)
    {
        $routingContext = new RoutingContext($app->getRequest(), $route);
        $handle = $route->getHandle();
        $pipes = $route->getPipes();
        $response = call_user_func(array_reduce(
            array_reverse($pipes),
            function ($stack, $pipe) {
                // $pipe is middleware
                return function () use ($pipe, $stack) {
                    return call_user_func($pipe, $stack);
                };
            },
            function () use ($handle, $routingContext) {
                // $handle is controller
                list($controller, $action) = explode('@', $handle);
                return call_user_func_array([new $controller, $action], [$routingContext]);
            }
        ));
        return [$app, $response];
    }

    public function onResponse(Kernel $app, $response = null)
    {
        $response = new Response([
            Response::STATUS => ResponseStatus::HTTP_OK,
            Response::BODY => $response
        ]);
        $app->getServer()->handleResponse($response);
        return $app;
    }

    public function onEnd(Kernel $app)
    {
        // TODO: Implement onEnd() method.
    }

}